package cn.edu.abtu.controller;

import cn.edu.abtu.config.redis.RedisService;
import cn.edu.abtu.entity.SysPermission;
import cn.edu.abtu.entity.SysUser;
import cn.edu.abtu.entity.UserInfo;
import cn.edu.abtu.service.SysUserService;

import cn.edu.abtu.utils.AjaxResult;
import cn.edu.abtu.utils.JwtUtils;
import cn.edu.abtu.utils.MenuTree;
import cn.edu.abtu.vo.RouterVo;
import cn.edu.abtu.vo.TokenVo;
import cn.edu.abtu.vo.query.UserQueryVo;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@RestController
@RequestMapping("/api/sysUser")
public class SysUserController {

    @Resource
    private RedisService redisService;

    @Resource
    private JwtUtils jwtUtils;

    @Resource
    private SysUserService sysUserService;

    @Resource
    private PasswordEncoder passwordEncoder;


    @PostMapping("/refreshToken")
    public AjaxResult refreshToken(HttpServletRequest request) {
        String token = request.getHeader("token");
        if (Objects.isNull(token)) {
            token = request.getParameter("token");
        }
        // 从Spring Security上下文中获取用户信息  (CheckTokenFilter中已经将认证的信息交给Spring Security上下文)
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        // 获取身份信息
        UserDetails userDetails = (UserDetails) authentication.getPrincipal();
        // 重新生成token
        String refreshToken = "";
        // 验证原来的token是否合法
        if (jwtUtils.validateToken(token, userDetails)) {
            // 生成新的token
            refreshToken = jwtUtils.generateToken(userDetails);
        }
        // 获取本次token的到期时间,交给前端做判断
        long expireTime = Jwts.parser().setSigningKey(jwtUtils.getSecret())
                .parseClaimsJws(refreshToken.replace("jwt_", ""))
                .getBody().getExpiration().getTime();
        //清除原来的token信息
        String oldToken = "token_" + token;
        redisService.remove(oldToken);
        // 存储新的token
        String newToken = "token_" + refreshToken;
        redisService.set(newToken, refreshToken, jwtUtils.getExpiration() / 1000);
        // 创建TokenVo对象
        TokenVo tokenVo = new TokenVo(expireTime, refreshToken);
        return AjaxResult.success("token生成成功! ", tokenVo);
    }

    @GetMapping("/getInfo")
    public AjaxResult getInfo() {
        // 从Spring Security上下文中获取用户信息  (CheckTokenFilter中已经将认证的信息交给Spring Security上下文)
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        // 判断用户信息是否未空
        if (Objects.isNull(authentication)) {
            return AjaxResult.error("用户信息查询失败! ", null);
        }
        // 获取用户信息
        SysUser sysUser = (SysUser) authentication.getPrincipal();
        // 获取该用户拥有的权限信息
        List<SysPermission> permissionList = sysUser.getPermissionList();
        // 获取权限编码
        Object[] roles = permissionList.stream().filter(Objects::nonNull).map(SysPermission::getCode).toArray();
        // 创建用户信息
        UserInfo userInfo = new UserInfo(sysUser.getId(), sysUser.getUsername(), sysUser.getAvatar(), null, roles);
        return AjaxResult.success("用户信息查询成功! ", userInfo);
    }

    // 获取菜单数据
    @GetMapping("/getMenuList")
    public AjaxResult getMenuList() {
        // 从Spring Security上下文中获取用户信息  (CheckTokenFilter中已经将认证的信息交给Spring Security上下文)
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        SysUser sysUser = (SysUser) authentication.getPrincipal();
        List<SysPermission> permissionList = sysUser.getPermissionList();
        List<SysPermission> collect = permissionList.stream()
                .filter(item -> item != null && item.getType() != 2)
                .collect(Collectors.toList());
        List<RouterVo> routerVoList = MenuTree.makeRouter(collect, 0L);
        return AjaxResult.success("菜单数据获取成功!", routerVoList);
    }

    @PostMapping("/logout")
    public AjaxResult logout(HttpServletRequest request, HttpServletResponse response) {
        String token = request.getHeader("token");
        if (Objects.isNull(token)) {
            token = request.getParameter("token");
        }
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (Objects.nonNull(authentication)) {
            // 清除Spring Security上下文中的用户信息
            new SecurityContextLogoutHandler().logout(request, response, authentication);
            // 清除redis缓存中的token
            redisService.remove("token_" + token);
            return AjaxResult.success("用户退出成功! ",null);
        }
        return AjaxResult.error("用户退出失败! ",null);
    }

    @GetMapping("/page")
    public AjaxResult page(UserQueryVo userQueryVo){
        return sysUserService.page(userQueryVo);
    }

    @PostMapping("/add")
    public AjaxResult add(@RequestBody SysUser sysUser){
        SysUser user = sysUserService.getUserByUsername(sysUser.getUsername());
        sysUser.setIsDelete(0);
        if (Objects.nonNull(user)){
            return AjaxResult.error("用户名已存在,请重新输入!");
        }
        sysUser.setPassword(passwordEncoder.encode(sysUser.getPassword()));
        boolean save = sysUserService.save(sysUser);
        if (save){
            return AjaxResult.success("用户添加成功!");
        }
        return AjaxResult.error("用户添加失败!");
    }

    @PutMapping("/update")
    public AjaxResult update(@RequestBody SysUser sysUser){
        Long userId = sysUser.getId();
        SysUser user = sysUserService.getById(userId);
        if (Objects.nonNull(user) && !user.getUsername().equals(sysUser.getUsername())){
            return AjaxResult.error("该用户名已被占用,不可以被修改!");
        }
        boolean result = sysUserService.updateById(sysUser);
        if (result){
            return AjaxResult.success("用户信息修改成功!",null);
        }
        return AjaxResult.error("用户信息修改失败!",null);
    }

    @DeleteMapping("/delete/{id}")
    public AjaxResult delete(@PathVariable Long id){
        boolean result = sysUserService.deleteById(id);
        if (result){
            return AjaxResult.success("删除用户信息成功!",null);
        }
        return AjaxResult.error("删除用户信息失败",null);
    }
}

